Эволюция способов работы с данными
Методы MoveFirst, MoveLast, MoveNext и MovePrevious
Свойство PageCount, PageSize и AbsolutePage
В первых статьях серии «<% ASP на блюдечке %>» мы познакомились с ASP, даже можно сказать, изучили тонкости построения разнообразнейших Web-интерфейсов с его помощью, но, как это ни странно, обходили стороной описание компонентов ADO, хотя и использовали некоторые из них для работы с базами данных.
Настоящая статья предназначена для тех, кто хотел бы ознакомиться с основами применения компонентов ADO, тем более что теперь, рассмотрев основы ASP, SQL и принципы проектирования баз данных, сделать это будет достаточно просто. Но и это еще не все. В довершение предлагаю познакомиться с новоявленным ADO — ADO+ и понять, что же является общим, а также вникнуть в различия между ADO и ADO+.
ADO (ActiveX Data Objects) — так называемые объекты данных ActiveX, представляют собой мощные интегрированные средства для создания приложений для работы с базами данных. Под приложениями при этом следует понимать не только приложения-программы, но и Web-приложения.
С самых первых дней своего существования программные приложения служили для манипуляций с разнообразнейшими данными. Вначале данные были разрозненными и не структурированными. Постепенно их стали упорядочивать в более регулярные структуры — базы данных. Затем, по мере развития и совершенствования, базы данных переросли из локальных в более общие — распределенные. И хотя это, с одной стороны, несколько усложнило обработку баз данных, суть задач, связанных с процессами обработки, не изменилась. Эволюция породила системы упорядочивания, структуризации и управления данными — серверы баз данных. Первоначально наиважнейшей характеристикой серверов БД считалась их низкая стоимость, в жертву которой зачастую приносилась производительность и масштабируемость. На этом этапе развития архитектура приложений состояла из двух компонентов: клиента и сервера. Последний разрабатывался специально для установленного сервера БД, требования которого к операционной системе были весьма специфичными. О переходе к другому серверу БД не могло быть и речи, поскольку системы того поколения были несогласованными.
Современный подход, предложенный специалистами-разработчиками Microsoft, позволил выполнять однотипные манипуляции над разнообразнейшими наборами данных, вне зависимости от их внутренней структуры и типа сервера БД. Этот подход вошел в историю под названием UDAS (Universal Data Access Strategy), а архитектура разработки приложений в соответствии с ним известна как OLE DB. Microsoft ADO по сути представляет собой интерфейс промежуточного уровня, позволяющий создавать приложения, работающие со всевозможными, разнообразными как по своей структуре, так и по своему происхождению (серверу) базами данных единообразно, максимально просто и оптимизированно. ADO — инструмент для создания приложений в соответствии с концепцией OLE DB.
Конечно, у ADO есть свои плюсы и свои минусы. К последним, в частности, относится невозможность использования технологии вне операционных систем, поддерживающих технологию COM (вследствие того, что сами компоненты ADO являются COM- модулями). Однако плюсы при этом выглядят куда более внушительно: быстрый и удобный интерфейс к базам данных на самом высоком уровне, полнейшая переносимость разрабатываемых приложений для работы с другими базами данных.
В основе технологии ADO лежит объектный подход к программированию. Объекты ADO, как и всякие другие объекты, имеют свои свойства и методы, служащие для обеспечения работы с базами данных. Эти объекты, в частности, доступны в среде ASP и функционируют на уровне OLE DB. Благодаря применению ADO программы становятся легко читаемыми и эффективными.
При использовании объектов ADO в ASP-приложениях для подключения к серверу баз данных применяются соответствующие ODBC-драйверы.
Модель объектов ADO довольно обширна. Однако в рамках настоящей статьи мы будем рассматривать лишь те объекты ADO, без которых процесс построения Web-интерфейсов к базам данных невозможен. Эти «незаменимые компоненты» можно условно разделить на пять функциональных групп, каждая из которых используется для решения определенного круга задач:
Структурная схема модели объектов ADO представляется следующим образом: .
Основа всех соединений с базой данных в модели ADO представлена методом Connection. Прежде чем выполнять какие бы то ни было манипуляции с любым из объектов ADO, требуется соединиться с базой данных (создать экземпляр объекта типа Connection):
<% Set db = Server.CreateObject(“ADODB.Connection”) ...
Рассмотрим теперь свойства объекта Connection
db.ConnectionTimeout = 15 db.CommandTimeout = 45 db.ConnectionTimeout = 15 db.Mode = adModeShareDenyRead db.Open connStr … %>
Свойство CommandTimeout — это свойство, позволяющее задать интервал времени в секундах, выделяемый на выполнение команды серверу. Значение этого интервала времени может быть как увеличено (при выполнении сложных запросов), так и уменьшено (в случае простых запросов). Правильная установка значения этого свойства крайне важна по той причине, что является индикатором загруженности сервера. Если, к примеру, выполнение того или иного запроса затягивается (количество одновременно подключенных пользователей резко возросло), то во избежание длительных простоев необходимо «принять меры». Средством, позволяющим оценить эту ситуацию, и является свойство CommandTimeout объекта Connection.
Свойство ConnectionString указывает строку, передаваемую драйверу OLE DB для инициализации источника данных ODBC.
Например:
db.Open “DSN=ishop; UID=sa;PWD=;database=ishop”
Свойство ConnectionTimeout — аналогично свойству CommandTimeout предназначено для контроля над скоростью работы с базой данных, а именно для контроля над скоростью подключения к ней. Надо отметить, что на это значение оказывает влияние и скорость передачи данных (что принципиально в случаях, когда речь идет об удаленной базе данных). По умолчанию значение этого свойства равно 15 сек.
DefaultDatabase — позволяет задать имя базы данных, автоматическое соединение с которой будет выполнено по открытии объекта Connection.
Свойство Mode — определяет тип доступа к базе данных и выполняет определенную оптимизацию соединения в соответствии с выставляемым значением. Поясним это на следующем примере. Предположим, что операции изменения с базой данных выполняться не будут. В этом случае целесообразно открыть ее со свойством Mode = adRead (то есть только для чтения), и это укажет ядру базы данных, что операции изменения производиться не будут. А поскольку ядро базы данных не встраивает поддержку «ненужных» функций в соединение, открытое с заданными свойствами, достигается определенный уровень повышения производительности. Еще одно преимущество свойства mode заключается в том, что в определенных ситуациях оно позволяет получить гарантированный монопольный доступ к определенным категориям данных, что, в свою очередь, зачастую является практически единственным способом сохранить целостность базы данных. Например, когда определенные изменения в базе данных должны быть произведены в так называемом горячем режиме (в подключенном и эксплуатируемом активном состоянии).
Возможные значения свойства Mode
Константа | Значение | Описание |
---|---|---|
adModeUnknown | 0 | Неявный тип доступа. Доступ по умолчанию |
adModeRead | 1 | Только чтение |
adModeWrite | 2 | Только запись |
adModeReadWrite | 3 | Чтение и запись |
adModeShareDenyRead | 4 | Монопольный доступ только чтение |
adModeSharedenyWrite | 8 | Монопольный доступ только запись |
adModeShareExclusive | 12 | Монопольный доступ — как для чтения, так и для записи |
adModeShareDenyNone | 16 | Монопольный доступ к источнику |
Свойство Provider — служит для указания альтернативного драйвера ODBC. Но поскольку в составе OLE DB имеются драйверы практически ко всем современным базам данных, использование этого свойства, скорее всего, не потребуется.
Метод Close — закрывает соединение с базой данных и все связанные с закрываемым соединением объекты RecordSet.
db.Close Set db = Nothing
Выполнение этой процедуры, тем не менее, не является обязательным, хотя оно и желательно, так как автоматическое отключение активного соединения выполняется лишь при переходе пользователя на другую страницу, при запуске другого приложения или через 20 минут после ухода с Web-сервера, а открытое соединение занимает ресурс памяти сервера, и незакрытые соединения могут поставить сервер в тупик, что особенно важно при больших транзакционных нагрузках на сервер.
Метод Execute — позволяет послать SQL-команду непосредственно ядру базы данных без использования объекта RecordSet. Использование этого метода целесообразно в том случае, когда должны быть выполнены определенные действия, не возвращающие объект типа RecordSet. Например:
…
Set db = Server.CreateObject(“ADODB.Connection”) db.Execute “UPDATE Articles SET Type = 1” …
Метод Open — открытие соединения. Метод служит для открытия доступа к базе данных и должен вызываться всякий раз перед использованием методов и коллекций объекта Connection. Пока не установлены требуемые значения свойств соединения и не осуществлен вызов метода Open, работа с объектом Recordest или с другими связанными с соединением объектами невозможна. В методе Open предусмотрено несколько параметров, каждый из которых предназначен для точного определения способа установки соединения и методов обмена информацией с базой данных.
Например:
… Set db = Server.CreateObject("ADODB.Connection") db.Open "Articles" …
Как видите, параметры UserID и Password не являются обязательными и при необходимости их значения автоматически выбираются из свойств объекта Connection. Проще говоря, если значения свойств объекта Connection уже были установлены, то указывать какие-либо параметры для вызова метода Open нет необходимости. Однако в некоторых ситуациях может потребоваться, чтобы значения этих параметров отличались от тех, что были установлены при подключении к базе данных, например, если требуется открыть соединение другому пользователю базы данных (с другими правами доступа к данным).
После установки соединения с сервером базы данных можно перейти к выполнению требуемой обработки данных в таблицах базы данных. Единственным условием для выполнения всех действий является наличие открытого объекта Connection. Именно через этот объект осуществляется доступ к объектам Command и Recordset. Кроме того, объект Connection может быть использован для посылки команд и операторов языка SQL непосредственно в ядро базы данных, без использования в качестве промежуточного звена объекта Recordset.
Для работы с сервером могут быть использованы два различных объекта — Command и Recordset. Практически вся необходимая обработка данных выполняется с помощью объекта Recordset, поскольку его набор свойств и методов обеспечивает возможность универсальной обработки столбцов таблиц базы данных и помещенных в них значений.
Объект Command является основополагающим в ходе выполнения любого сеанса ADO соединения с БД. Он используется для создания экземпляра объекта Recordset, по сути являющегося областью хранения промежуточных значений (этаким кэшем) и предоставляющим возможность быстрого обращения к элементам (например, определенной выборки) базы данных. Это позволяет сэкономить временные и аппаратные ресурсы сервера, поскольку в данном случае транзакции с сервером выполняются лишь с целью извлечения каждого конкретного набора отдельных значений (выборки), а вся дальнейшая обработка сводится к операциям над уже извлеченным набором как над отдельным объектом Recordset. Кроме того, следует понимать, что благодаря наличию всего одного (вместо нескольких) соединения с сервером в данном случае возможно извлечение многих значений или их наборов, что, естественно, позволяет как значительно повысить вычислительную производительность сервера, так и соптимизировать создаваемое приложение.
Метод Execute применяется для выполнения любых команд языка SQL, независимо от того, будут в результате выполнения команды возвращаться какие-либо данные (результаты запросов) или нет. Этот метод может использоваться и для выполнения на сервере команд администрирования или поддержки базы данных (вызов хранимых процедур — наиболее типичный случай).
Разумеется, метод Execute может быть применен и для выборки помещаемых в объект Recordset данных, поскольку он позволяет использовать посылаемую на сервер команду для определения содержания этого объекта. Существует два способа вызова метода Execute, применение которых зависит от того, куда следует поместить полученные результаты. Если результаты выполнения команды должны быть помещены в объект Recordset — для вызова метода используется приведенный ниже синтаксис.
Set OwnRecordset = OwnCommand.Execute (команда, число_строк, режим)
К примеру:
'Создадим экземпляр объекта типа соединение и откроем его Set objConn = Server.CreateObject("ADODB.Connection") objConn.Open "DSN=Sailors" 'Создадим экземпляр объекта типа команда Set objCmd = Server.CreateObject("ADODB.Command") 'Зададим свойства командного объекта Set objCmd.ActiveConnection = objConn objCmd.CommandText = strInsert & ") " & strValues & ")" objCmd.CommandType = adCmdText 'И выполним его objCmd.Execute
В этом случае объект Connection используется для передачи команды SQL, указанной в качестве значения параметра команда. Команда может быть представлена практически в любой допустимой форме, а не только в операторе выборки SELECT. Для этого можно просто указать в качестве значения параметра команды имя таблицы, а в параметре режима выставить значение adCmdTable, что будет соответствовать режиму извлечения содержимого всей таблицы с заданным именем. Аналогично для выполнения хранимой процедуры достаточно просто указать ее имя и соответствующий режим. Однако при довольно сложных многотабличных запросах такая форма записи, разумеется, непригодна, и приходится пользоваться довольно сложными SQL-конструкциями, например:
sSQL = "SELECT * FROM AdvertFormat" sSQL = sSQL & " LEFT OUTER JOIN AdvertDetails ON AdvertDetails.FormatID = AdvertFormat.ID" sSQL = sSQL & " LEFT OUTER JOIN MNumber ON MNumber.NumberID = AdvertDetails.MagazineID" sSQL = sSQL & " LEFT OUTER JOIN Magazine ON Magazine.MagazineID = MNumber.MagazineID" sSQL = sSQL & " LEFT OUTER JOIN AdvertLayout ON AdvertLayout.ID = AdvertFormat.LayoutID" sSQL = sSQL & " WHERE (AdvertDetails.FirmID = " & AnsiString (FirmID); sSQL = sSQL & ") AND (AdvertDetails.PayerID = " & AnsiString(PayerID); sSQL = sSQL & ") AND (AdvertDetails.MagazineID = " & AnsiString(MagazineID) & ")"
Set rs = db.Execute(sSQL)
Если метод Execute используется для непосредственной обработки информации, внесения изменений в структуру таблицы или выполнения любых других операций, не требующих создания объекта Recordset, то вызов этого метода может быть осуществлен в следующей форме:
command.Execute команда, число_строк, режим
Различие состоит в том, что выполняется простой вызов данного метода, причем после его выполнения не ожидается возвращения каких-либо значений, кроме параметра число_строк, если он имеет смысл. Суть в том, что параметры в команде не нужно брать в скобки. Если вы достаточно хорошо знакомы с Visual Basic, смысл происходящего должен быть вам понятен. При создании объекта Recordset метод Execute вызывался как функция, возвращающая значения. В данном же случае при использовании метода Execute для решения других задач он вызывается как подпрограмма.
Поясним сказанное на двух примерах:
Вызов SQL оператора UPDATE для обновления содержимого таблицы SQLUpdate = "UPDATE Show " &_ "SET Show.free_seats=" & free_seats & " " &_ " WHERE Show_ID=" & show_id conn.Execute(SQLupdate) Вызов SQL оператора INSERT для вставки новой записи в таблицу SQLquery = "SELECT max([Booking_ID]) as bookingnumber FROM booking" Set rsBooking = conn.execute(SQLquery) maxbookid = rsBooking("bookingnumber") + 1 SQLinsert = "INSERT INTO Booking ( show_id, booked_seats ) " & _ "VALUES ('" & show_id & "', '" & tickets & "')" conn.Execute(SQLinsert)
Свойство ActiveConnection используется для указания объекта Connection, с которым связан данный объект Command. Если вызов методов объекта Command (например, метода Execute) выполнен до присвоения значения этому свойству, то результатом выполнения будет ошибка. Имя используемого соединения должно быть указано заранее, например следующим кодом:
Set objCmd = Server.CreateObject("ADODB.Command") Set objCmd.ActiveConnection = objConn
Если необходимо изменить соединение, с которым связан данный объект Command, следует присвоить свойству ActiveConnection значение Nothing, после чего поместить в него новое значение, как было показано выше. Сделать это стоит потому, что фактически операции типа:
objCmd.ActiveConnection = Nothing
будет произведено удаление указателя на экземпляр объекта типа Recordset. К примеру:
… Set DataConn = Server.CreateObject("ADODB.Connection") DataConn.Open "softwing" Set cmdTemp = Server.CreateObject("ADODB.Command") cmdTemp.CommandText = sql cmdTemp.CommandType = 1 Set cmdTemp.ActiveConnection = Nothing Set cmdTemp.ActiveConnection = DataConn cmdTemp.Execute Set cmdTemp = Nothing Set DataConn = Nothing …
Как вы уже, вероятно, догадались, свойство CommandText содержит текущую командную строку, которую необходимо передать драйверу соединения для выполнения в базе данных. Это, по сути, текст команды, которую требуется выполнить. Сюда можно поместить любую команду языка SQL, имя хранимой процедуры или имя таблицы. Если указывается имя хранимой процедуры, то следует либо — поместить перед ним SQL-команду EXEC, либо присвоить параметру режим метода Execute-значение, указывающее на обращение к хранимой процедуре.
К примеру:
objCmd.CommandText = “exec sp_additem @cartid, @itemid, @qty”
Свойство CommandTimeout является незаменимым и используется для контроля вычислительной нагрузки на сервер и на коммуникационное оборудование, что особенно существенно при создании Internet-приложений. Свойство CommandTimeout может использоваться для представления пользователю некоторых средств контроля над соединением. В свойстве CommandTimeout указывается временной интервал, на протяжении которого объект ADO будет ожидать завершения выполнения данной команды. По умолчанию принимается значение 30 — в обычной ситуации этого вполне достаточно. Однако не следует забывать о некоторых факторах, которые могут повлиять на выбираемое для данного свойства значение, например:
objCmd. CommandTimeout = 60
Если выполняемый запрос достаточно сложен, может потребоваться увеличение значения этого свойства, чтобы предоставить запросу достаточно времени для его завершения. В подобных случаях следует выполнить серию экспериментов, цель которых будет состоять не только в определении среднего приемлемого времени выполнения данного запроса, но и в выявлении случаев чрезмерного ожидания его завершения, указывающих на наличие в системе определенных проблем вычислительного характера. Установку значения свойства CommandTimeout лучше всего выполнить в файле global.asa. Подобный подход придаст дополнительную гибкость процедуре внесения изменений в масштабе всего приложения, если в этом возникнет необходимость. Вместо анализа и корректировки текстов множества файлов достаточно будет изменить одну строку глобального определения данного значения.
Наиважнейшим компонентом ADO является компонент набора данных (recordset). Набор данных — это копия определенного фрагмента базы данных в памяти компьютера, сохраняющая структуру последней. Набор данных представляет так называемое пассивное (не подключенное) к базе данных состояние, то есть фрагмент базы данных присутствует в памяти компьютера, хотя соединение с реальной базой данных уже закрыто. Этот объект предоставляет разработчику широкий набор функциональных возможностей; благодаря ему можно выполнять практически любую обработку выбранной из базы данных информации. Обработка может выполняться как динамически — на основе опроса объекта Recordset о структуре таблицы, так и статически — когда все выполняемые над данными действия жестко закодированы в приложении. В качестве примера рассмотрим следующий простой код, формирующий список ссылок на статьи газетного сайта из базы данных в зависимости от характера самих данных (текстовых или html-файлов):
<% Set db = Server.CreateObject("ADODB.Connection") db.Open "Articles" sSQL = "SELECT * FROM Articles Where IsTopNew = '1' Order By ID DESC" Set rs = db.Execute(sSQL) Cnt = 0 Do While NOT Rs.EOF If rs.Fields("Article").value <> "No Text" Then Link = "<a href= http://localhost/ArtTempl.asp?id=" & rs.Fields("ID").value & ">" &_ "rs.Fields("Title").value & "</a>"
Else Link = "<a href= http://localhost/Articles/" & rs.Fields("TextFile").value & ">" &_ "rs.Fields("Title").value & "</a>"
End If
Response.Write Link & "<br>" Response.Write "<i>By " & rs.Fields("Author").value & "</i><br>" ANN = rs.Fields("Annotation").value If ANN <> "NA" Then Response.Write ANN End If Rs.MoveNext Cnt = Cnt + 1 Loop
db.Close Set db = Nothing %>
Коллекция Fields — важнейший элемент объекта Recordset. Она содержит информацию, необходимую для работы с выбранными из таблиц данными. Свойства, связанные с каждым из полей в коллекции, содержат его исчерпывающее описание — от установленного в таблице типа и размера этого поля до имени для реальной длины его значения.
Для доступа к этим свойствам необходимо знать имя требуемого поля и название интересующего нас свойства, например, строка вида rs.Fields("Article").value указывает на значение поля Article текущей записи активной таблицы открытой базы данных (см. вышеприведенный пример).
Свойство Name (Имя) используется для указания имени столбца таблицы базы данных, например:
<% howmanyfields = rs.fields.count - 1 for I = 0 to howmanyfields Response.Write rs.fields(i).name Response.Write “<BR>” next %>
Подобный подход позволяет создавать Web-страницы с динамически изменяющимся содержимым, в которых имена полей таблиц могут использоваться, в частности, для построения заголовков.
Свойство Value содержит значение, выбранное из поля таблицы. Для определения текущего типа представления данных предназначено свойство Type. Если данные в программе, в зависимости от их типа, должны обрабатываться по-разному, свойство Type может быть использовано для выбора варианта обработки. Подобные действия необходимо осуществлять перед выполнением сравнений, вычислением значения выражений и т.п. Приведем несколько примеров выражений с использованием значений полей таблицы. Например, выражение
If rs.Fields("Article").value <> "No Text" Then…
позволяет сравнить значение, хранящееся в поле Article, с текстовой константой «No Text».
If rs.Fields("Article").type = "int" Then…
Позволяет определить, является ли тип поля Articles целочисленным.
Пара методов, AddNew и Update, позволяет добавлять новую запись к объекту Recordset и заносить значение ее полей перед добавлением в базу данных. После вызова метода AddNew полям новой записи присваиваются требуемые значения и вызывается метод Update, сохраняющий эти данные в таблице. Если не вызывать метод AddNew, вместо добавления новой записи будет выполнено обновление полей текущей записи объекта Recordset. Рассмотрим пример использования пары методов, AddNew и Update:
<% … Rset.AddNew
Rset.Fields (“PinCode”) = 12107880 Rset.Update … %>
При использовании комбинации методов AddNew/Update можно получить практически тот же результат, что и при применении SQL-команды INSERT INTO посредством метода Execute объекта Command, с одним только отличием. Оно состоит в том, что после вызова метода Update состояние объекта Recordset обновляется и в него добавляется новая строка, в то время как при использовании команды INSERT INTO требуется дополнительно выполнять обновление текущего объекта Recordset для того, чтобы в него попали только что введенные значения. Оба подхода равнозначны, однако подход с использованием метода AddNew следует считать более последовательным и лучше выдержанным в том стиле, который используется в технологии ADO для работы с базами данных и их таблицами. Можно вызвать метод AddNew и внести изменения в объект Recordset, после чего вновь вызвать метод AddNew, прежде чем обратиться к методу Update. В этом случае ADO автоматически вызовет метод Update до выполнения очистки текущей записи объекта Recordset с целью вставки новой записи. Однако при добавлении записей все же рекомендуется всегда явно вызывать метод Update. В результате вы будете иметь гарантию того, что все внесенные изменения зафиксированы в базе данных. Более того, данный стиль программирования обеспечивает более читаемый код.
В качестве параметра методу AddNew можно передать коллекцию типа Fields. Это вызовет одновременное обновление нескольких полей. В данном случае ADO переключает функцию обновления в режим Batch. Для внесения новых записей в базу данных, вместо вызова метода Update, в данном случае потребуется метод UpdateBatch. То же самое следует применять и при одновременном добавлении значений нескольких полей в запись таблицы, к примеру:
<% … Dim oRS set oRS=server.CreateObject("adodb.recordset") oRS.Open "BoatClass", "DSN=Sailors", adOpenDynamic, adLockPessimistic oRS.AddNew oRS("ClassName") = varClassName oRS("ClassLength") = varClassLength oRS("ClassWeight") = varClassWeight oRS("ClassEntered") = varClassEntered oRS.UpdateBatch
… %>
SQL-альтернативой использованию методов AddNew / Update, как уже отмечалось, служит SQL-оператор Insert:
<% … sqlQuery = "INSERT INTO Orders (StaffID, SKU, Qty, OrderDate) Values ('" & Session("StaffID") & "','" & Request.QueryString("SKU") & "',1,'" & date & "')" On Error Resume Next set rs = conn.Execute(sqlQuery) rs.Close
… %>
Как и в других объектах ADO, метод Close объекта Recordset закрывает этот объект и освобождает все связанные с ним ресурсы. По окончании работы с объектом Recordset его нужно обязательно закрыть, поскольку при этом освобождаются ресурсы и на стороне сервера. (Данные ресурсы необходимо освобождать как можно раньше, это снижает конкуренцию за владение ими среди многочисленных пользователей базы данных.) И рекомендуется при закрытии присваивать указателю на объект Recordset константу Nothing, поскольку именно при этом производится фактическое удаление указателя на экземпляр объекта.
Например:
Rset.Close Set Rset = Nothing
Метод Delete предназначен для удаления текущей строки из объекта Recordset и связанной с ним таблицы в базе данных. При использовании метода Delete можно заранее определять условия для удаления нескольких записей из базы данных с помощью свойства Filter, предварительно поместив в него критерий удаления.
Если удаление записей выполняется в пакетном режиме (удаляется сразу несколько записей), то для фактического удаления из таблицы базы данных записей, отмеченных к удалению, следует вызвать метод UpdateBatch. Если этого не сделать, изменения будут утеряны и записи не будут удалены из таблицы.
Несмотря на это, альтернативный вариант удаления с использованием SQL-команды используется довольно часто:
… strSQL = "Delete * from Clubs Where ClubCode = '" & _ Request.Form("cboClubs") & "'" Set objConn = Server.CreateObject("ADODB.Connection") objConn.Open "DSN=Sailors" Set objCmd = Server.CreateObject("ADODB.Command") Set objCmd.ActiveConnection = objConn objCmd.CommandText = strSQL objCmd.CommandType = adCmdText objCmd.Execute …
При использовании в технологии ADO следует четко понимать назначение методов MoveFirst, MoveLast, MoveNext и MovePrevious. Эти методы предназначены для навигации среди записей объекта Recordset путем перемещения среди записей и элементов выбранного из базы набора данных.
Из названия свойства RecordCount (Счетчик строк) следует, что для получения конкретного значения числа строк в объекте Recordset следует предварительно вызвать метод MoveLast. Причина в том, что содержимое буфера объекта Recordset и способ его связи с исходными таблицами динамически изменяются. До тех пор пока из источника данных не будут получены все выбранные строки, драйвер доступа к базе данных не сможет определить их общее количество. В целом назначение отдельных методов Move понятно из их названия. Каждый из них обеспечивает определенный тип перемещения в буфере данных объекта Recordset.
MoveFirst — используется для перемещения к первой записи в наборе данных Recordset. При вызове этого метода свойству BOF автоматически присваивается значение TRUE.
MoveLast — используется для перемещения к следующей записи в наборе данных Recordset. При вызове этого метода свойству EOF автоматически присваивается значение TRUE.
Пример использования MoveNext и MoveLast — подпрограмма корректной установки курсора на последнее значение:
SUB MoveNext_OnClick On Error Resume Next ADC.Recordset.MoveNext IF ERR.Number <> 0 THEN ADC.Recordset.MoveLast END IF END SUB
MoveNext — используется для перемещения к следующей по отношению к текущей позиции в наборе данных Recordset записи. Если при этом будет достигнут конец набора данных, свойству EOF будет присвоено значение TRUE. Если требуется установить условие EOF искусственно, следует вызвать метод MoveLast для перехода к последней записи набора данных.
MovePrevious — используется для перемещения к предыдущей по отношению к текущей позиции в наборе данных Recordset записи. Если при этом достигнуто начало набора данных, свойству BOF будет присвоено значение TRUE. Если требуется установить условие BOF искусственно, следует вызвать метод MoveFirst для перехода к первой записи набора данных. Пример использования MoveFirst и MovePrevious — подпрограмма корректной установки курсора на первое значение:
SUB MovePrev_OnClick On Error Resume Next ADC.Recordset.MovePrevious IF ERR.Number <> 0 THEN ADC.Recordset.MoveFirst END IF END SUB
Прежде чем начинать обрабатывать наборы данных следует, как известно, открыть этот набор данных. При этом устанавливается соединение между данным объектом и требуемыми таблицами базы данных. При вызове метода Open объекта Recordset следует указать несколько параметров, определяющих способ представления информации, возможность внесения в нее изменений и т.п. Ниже приведен общий синтаксис вызова метода Open:
RSet.Open SQL-команда, соединение, тип_курсора, тип_блокировки, режим
Вместо параметра SQL-команда указывается одна или несколько команд языка SQL, разделяемых точкой с запятой. Эта команда будет либо использована для выработки информации из таблиц базы данных, либо переделана для обработки и выполнения ядру базы данных. Обратите внимание, что нет необходимости передавать на выполнение команду SELECT. Вместо этого можно указать имя таблицы базы данных или имя используемой хранимой процедуры и одновременно установить соответствующее значение в параметре «режим». Кроме того, можно сделать ссылку на уже существующий объект Command и использовать его как источник информации для данного объекта Recordset.
В параметре «соединение» указывается имя уже существующего объекта Connection. Если имя объекта соединения не будет указано, для данного объекта Recordset будет установлено новое соединение. При этом, если не будет предоставлена строка определения параметров соединения, установка нового соединения будет связана с новым подключением к серверу, которое будет учитываться последним как очередная выданная лицензия на подключение. В свете этих замечаний рекомендуется всегда ссылаться на уже существующий объект Connection.
Метод Update используется как для добавления новых строк (совместно с методом AddNew), так и для изменения строк, уже существующих в буфере объекта Recordset. После вызова метода AddNew для вставки пустой записи и заполнения ее полей требуемыми значениями следует вызвать метод Update для помещения новой записи в таблицы базы данных.
Если требуется изменить уже существующую запись, следует найти эту запись в буфере и внести в нее необходимые изменения. Завершив обновление, надо вызвать метод Update для фиксации внесенных изменений в таблицах базы данных.
Если значение этого свойства равно True, значит в настоящий момент указатель записи объекта Recordset установлен на начало файла или на первую запись в наборе. Эта ситуация всегда происходит после вызова метода MoveFirst.
Если значение этого свойства равно True, значит в настоящий момент указатель записи объекта Recordset установлен на конец набора данных. Эта ситуация всегда имеет место после вызова метода MoveLast. Кроме того, данная ситуация возникает при использовании метода MoveNext для последовательной обработки записей буфера, после того как обработаны все записи в буфере.
Свойства BOF и EOF являются ключевыми, и без них не обходится ни одно приложение. Эти свойства, как правило, используются в двух случаях:
Do While iRecordsShown < iPageSize And Not RS.EOF tid=rs("thread_id") ParentID=rs("id") name=rs("name") email=rs("email") subject=rs("subject") mesdate=rs("mesdate") response.write "<tr><td>" response.write image & "<a href='show.asp?id=" & parentID &_ "&fid="&fid&"&tid="&tid&"'>" & subject &_ "</a>" & "...." & mesdate & "...." & name & "</a>" response.write "</tr></td>" rs.movenext iRecordsShown = iRecordsShown+1 Loop
… SQLQuery = "SELECT * FROM Flights WHERE TimesID = " & Request("DateTime")set rsFlights = conn.Execute(SQLQuery) if rsFlights.eof then rsFlights.close set rsFlights = nothing Response.write("<p>Sorry, this flight is not available now!") Response.write("<br /><anchor title='") Response.write("ReStart'") Response.write(">Go Home to Restart-><go href='") Response.write("index.asp'") Response.write("/></anchor>") Response.write("</p></card></wml>") Response.end end if …
В свойство RecordCount помещается общее число записей набора данных объекта Recordset. Следует заметить, что, пока для перемещения в пределах буфера данных объекта Recordset не будет использован метод MoveLast или MoveNext, значение этого свойства будет соответствовать максимальному количеству просмотренных строк.
Набор этих свойств имеет колоссальное значение при разработке поисковых машин. Ведь результатом запроса пользователя может явиться огромное множество записей, и тогда имеет смысл предоставить пользователям возможность постраничного доступа к результатам запроса (составить интерфейс вида 1-5, 5-10, 10-15 и т.д). Для организации системы подобного доступа и применяются свойства PageCount, PageSize и AbsolutePage объекта RecordSet. Давайте рассмотрим, каким образом такую систему можно разработать самостоятельно:
<%@ LANGUAGE="VBScript" %> <%Response.Expires=0%> ' Будем обновлять страницу всякий раз, когда к ней будет происходить обращение … <% ' Получить номер текущей страницы
Select Case Request.QueryString("NPage") Case "" Session("CurrentPage") = 1 ' Мы на первой странице Case "Next" Session("CurrentPage") = Session("CurrentPage") + 1 ' Мы перешли на следующую страницу Case "Previous" Session("CurrentPage") = Session("CurrentPage") - 1 ' Мы перешли на следующую страницу End Select
' Определим переменные и константы
Dim objConnection Dim objRecordset Const adOpenKeyset = 1 ' Откроем базу данных
Set objConnection = Server.CreateObject("ADODB.Connection") objConnection.Open "Articles", "sa", ""
Dim strSQL
strSQL = strSQL & "SELECT Articles.Title, Titles.Title, " strSQL = strSQL & "Editors.EditorName FROM Authors, Titles, Publishers" strSQL = strSQL & "WHERE Authors.ID = 5 " strSQL = strSQL & "AND Titles.LetterIndex = 'L' " strSQL = strSQL & "AND Editors.Edition LIKE `OREILLY' " strSQL = strSQL & " ORDER BY Articles.Title"
Set objRecordset = Server.CreateObject("ADODB.Recordset") objRecordset.PageSize = 10 objRecordset.Open strSQL, objConnection, adOpenKeyset objRecordset.AbsolutePage = CLng(Session("CurrentPage")) ' Просмотрим результаты запроса
%> <P>Page <%=Session("CurrentPage")%> of <%=objRecordset.PageCount%></P> <TABLE BORDER> <TR> <TH>Автор</TH><TH> Заголовок</TH><TH>Редактор</TH> </TR> <% Dim I For i = 1 To objRecordset.PageSize ' Для каждого элемента страницы %> <TR> <TD><%=objRecordset("Author")%></TD> <TD><%=objRecordset("Title")%></TD> <TD><%=objRecordset("EditorName")%></TD> </TR> <% objRecordset.MoveNext Next %>
</TABLE>
<% If CLng(Session("CurrentPage")) < objRecordset.PageCount Then ' Если число виртуальных страниц пока не исчерпано, ' то сформируем ссылку на файл с этим исходным кодом ' и присвоим параметру значение %>
<P><A HREF="thisfilename.asp? NPage=Next">Вперед</A></P>
<% End If %> <% If CLng(Session("CurrentPage")) > 1 Then %> <P><A HREF=" thisfilename.asp? NPage=Prev">Назад</A></P> <%End If%>
<% objRecordset.Close objConnection.Close Set objRecordset = Nothing Set objConnection = Nothing %> …
ADO+ по своей сути — результат эволюции Microsoft ActiveX Data Objects (ADO), позволяющий создавать многоплатформенные приложения для доступа к разнообразным базам данных. Давайте попытаемся осознать лишь «надводную часть айсберга различий», которую нельзя не заметить «невооруженным глазом».
В частности, ключевым отличием является опора на XML (Extensible Markup Language) именно как на формат передачи данных и, как следствие, на то обстоятельство, что любое приложение, способное воспринимать формат XML, может обрабатывать данные. И еще здесь значительно улучшен синтаксис программирования (по сравнению с ADO), к примеру, вместо строки:
IF TotalCost > Table(«Customer»).Column(«AvailableCredit»)
может быть использована строка:
IF TotalCost > Customer.AvailableCredit
Помимо того что последнюю строку легче прочитать (она полнее отражает суть решаемой задачи), ее еще и легче написать — не правда ли? Но и это еще не все. Как известно, процессор автоматического заполнения выражений (automatic statement completion) чувствителен именно к программируемым объектам. В частности, теперь можно непосредственно выбрать, к примеру, из появившегося списка, требуемую таблицу только что набранного названия базы данных.
И это обеспечивает не только удобство при наборе, но и повышение производительности: теперь не нужно искать экземпляр данных среди объектов коллекции ADO (ADO collection) всякий раз, когда требуется обращение к этому экземпляру данных.
Из элементов же «подводной части айсберга отличий» можно указать концепцию отсоединенного состояния, введенную начиная с версии ADO 2.0. Это позволило разработчикам в значительной степени разгрузить серверы от выполнения вычислений, переложив их на компьютеры клиентов. Здесь весьма уместна параллель с динамическим программированием, когда взаимодействие между сервером и клиентом частично «смещено» в сторону последнего. Попросту говоря, эта концепция позволяет выполнять определенные операции над копиями наборов данных в памяти компьютера, при нахождении его в неподключенном к БД состоянии. Если вдуматься, то выгода от этого двойная: во-первых, экономится дорогой клиент-серверный канал передачи информации (промежуточные результаты не передаются, операции над наборами данных выполняются локально, а следовательно, быстрее), а во-вторых, сервер освобождается от выполнения вычислительных операций.
В ADO+ эта концепция значительно развита за счет введения нового класса DataSet (далеким потомком объекта RecordSet). Обект DataSet, в частности, позволяет динамически «держать» в памяти копии целой базы данных и выполнять все вычислительные операции именно над этим представлением базы данных, обновляя реальную базу данных лишь время от времени.
Однако мы не будем останавливаться на ADO+ в рамках настоящей публикации, поскольку это тема отдельной (и не одной) статьи…
КомпьютерПресс 2'2001